package com.lizhaoblog.pro006scheduled.annotation;

import com.lizhaoblog.pro006scheduled.common.RedisUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 * @time：
 * @Discription：
 */
@Aspect
@Component
public class RequestLimitAOP {
    @Autowired
    private RedisUtil redisUtil;
    private static final Logger logger = LoggerFactory.getLogger("RequestLimitAOP");
//    @before 注解代表在请求发送到控制器之前会先来到这里执行相应的内容，within里面的书写表示写在控制器上方并且有对应注解的控制器会来到这里。
//    在获得ip和对应的url之后将它作为一个key，存放到map中，假如map中已经存在了这个key，那么多产生一个时间处理器，当时间超过注解书写的单位时间之后又会将这个key从map中移走。
//    假如访问的次数超过了限制，将会抛出异常说明访问次数过多
//    @Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)")
@Before("@annotation(limit)")
    public void requestLimit(final JoinPoint joinPoint , RequestLimit limit) throws RequestLimitException {
        try {
            Object[] args = joinPoint.getArgs();
            HttpServletRequest request = null;
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletResponse response = servletRequestAttributes.getResponse();
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof HttpServletRequest) {
                    request = (HttpServletRequest) args[i];
                    break;
                }
            }
            if (request == null) {
                throw new RequestLimitException("方法中缺失HttpServletRequest参数");
            }
            String ip = request.getLocalAddr();
            String url = request.getRequestURL().toString();
            String key = "req-limit-".concat(url).concat(ip);
            if (redisUtil.get(key) == null || Integer.valueOf(redisUtil.get(key).toString()) == 0) {
                redisUtil.set(key,1,limit.time());
            } else {
                int count =Integer.valueOf(redisUtil.get(key).toString());
                if (count < limit.count()){
                    redisUtil.set(key, Integer.valueOf(redisUtil.get(key).toString()) + 1);
                }else{
                    logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
                    String toLomitPath ="http://" + request.getServerName()+ ":" + request.getServerPort()+"/limit";   //端口号
                    response.sendRedirect(toLomitPath);
                }
            }
        }catch (RequestLimitException e){
            throw e;
        }catch (Exception e){
            logger.error("发生异常",e);
        }
    }
}
